﻿//www.codeOften.com
//Senthil Maruthaiappan - senips (at) gmail.com
//see license on http://www.codeplex.com/Jinglebell


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace CodeOften.Container
{
    public class Services : IServices
    {
        private readonly Dictionary<Type, object> _svcInstances = new Dictionary<Type, object>();
        private readonly Dictionary<Type, Type> _svcTypes = new Dictionary<Type, Type>();

        #region IServices Members

        public void AddService<T>(Type t)
        {
            IEnumerable<KeyValuePair<Type, Type>> existingType = _svcTypes.Where(x => x.Key == typeof (T));
            if (existingType.Count() != 0)
                _svcTypes[typeof (T)] = t;
            else
                _svcTypes.Add(typeof (T), t);
        }

        public T CreateInstance<T>(params object[] parameters)
        {
            var instance = (T) Activator.CreateInstance(_svcTypes[typeof (T)], parameters);
            Type t = instance.GetType();
            PropertyInfo propInfo = t.GetProperty("Services");
            if (propInfo != null)
                propInfo.SetValue(instance, this, null);
            return instance;
        }


        public void AddService<T>(object svcObject)
        {
            IEnumerable<KeyValuePair<Type, object>> existingObj = _svcInstances.Where(x => x.Key == typeof (T));
            if (existingObj.Count() == 0)
                _svcInstances.Add(typeof (T), svcObject);
            else
                _svcInstances[typeof (T)] = svcObject;
        }

        public T Get<T>(params object[] parameters)
        {
            Type t = typeof (T);
            object obj = null;
            var result = (T) obj;
            IEnumerable<KeyValuePair<Type, object>> existingType = _svcInstances.Where(x => x.Key == typeof (T));
            if (existingType.Count() != 0)
            {
                result = (T) existingType.First().Value;
            }
            if (result == null)
            {
                object[] attribs = t.GetCustomAttributes(typeof (InstanceBehaviour), true);
                if (attribs.Length != 0)
                {
                    var insbehaviour = attribs[0] as InstanceBehaviour;
                    if (insbehaviour.InstanceBehaviourType == InstanceBehaviourType.AlwaysCreate)
                        return CreateInstance<T>(parameters);
                }
                result = CreateInstance<T>(parameters);
                AddService<T>(result);
            }
            return result;
        }

        #endregion
    }
}